package com.zitangkou.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.Gson;
import com.zitangkou.user.domain.*;
import com.zitangkou.common.enums.*;
import com.zitangkou.user.enums.user.CodeTypeEnum;
import com.zitangkou.user.enums.user.GenderEnum;
import com.zitangkou.user.enums.user.UserEnum;
import com.zitangkou.common.global.GlobalException;
import com.zitangkou.common.global.UserContent;
import com.zitangkou.user.info.RoleInfo;
import com.zitangkou.user.info.UserInfo;
import com.zitangkou.user.info.converter.IPermissionInfoConverter;
import com.zitangkou.user.info.converter.IRoleInfoConverter;
import com.zitangkou.user.info.converter.IUserInfoConverter;
import com.zitangkou.user.req.user.*;
import com.zitangkou.user.resp.user.ConstantListResp;
import com.zitangkou.user.resp.user.ConstantResp;
import com.zitangkou.user.resp.user.UserLoginResp;
import com.zitangkou.user.service.IUserService;
import com.zitangkou.user.util.CryptUtil;
import com.zitangkou.user.util.JwtUtil;
import com.zitangkou.user.util.RedisUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户
 *
 * @author Deng Ningning
 * @version 1.0
 * @date 2020/8/31 16:39
 */

@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private IUserDomainService userDomainService;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private IRoleDomainService roleDomainService;

    @Autowired
    private IPermissionDomainService permissionDomainService;

    @Resource
    private IUserPermissionDomainService userPermissionDomainService;

    @Resource
    private IRoleInfoConverter roleInfoConverter;

    @Resource
    private IUserInfoConverter userInfoConverter;

    @Resource
    private IPermissionInfoConverter permissionInfoConverter;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 分页查询用户
     *
     * @param req
     * @return com.zitangkou.common.global.PageResp<com.zitangkou.user.model.entity.UserDO>
     * @author Deng Ningning
     * @date 2020/9/1 14:16
     */
    @Override
    public IPage<UserInfo> getUserPage(GetUserByPageReq req, UserContent userContent) {
        IPage<UserDomain> page =
                userDomainService.selectPageByConditions(req.getCurrent(), req.getSize(), req.getKeyword(), req.getStatus());
        return new Page<UserInfo>().setCurrent(page.getCurrent()).setSize(page.getSize())
                .setRecords(userInfoConverter.toInfoList(page.getRecords()))
                .setTotal(page.getTotal());
    }

    @Override
    public boolean insertUser(AddUserReq req) {
        return false;
    }

    @Override
    public boolean updateUser(EditUserReq req) {
        return false;
    }

    @Override
    public boolean deleteUser(String userId) {
        return false;
    }

    /**
     * 用户账号登录
     *
     * @param req
     * @return com.zitangkou.user.model.resp.user.UserLoginResp
     * @author Deng Ningning
     * @date 2020/9/3 9:39
     */
    @Override
    public UserLoginResp accountLogin(AccountLoginReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        // 验证账号是否存在
        UserDomain userDomain = checkUserExist(enterpriseId, req.getUserAccount());
        // 验证密码
        validateUserPwd(userDomain, req.getUserPwd());
        // 生成 token 并缓存用户信息
        String token = generateTokenAndCache(userDomain);
        // 返回数据
        return new UserLoginResp()
                .setToken(token)
                .setGender(userDomain.getGender())
                .setHeadImg(userDomain.getHeadImg())
                .setNickname(userDomain.getNickname())
                .setUserAccount(userDomain.getUserAccount());
    }

    /**
     * 手机号码登录
     *
     * @param req
     * @return com.zitangkou.user.model.resp.user.UserLoginResp
     * @author Deng Ningning
     * @date 2020/9/12 13:20
     */
    @Override
    public UserLoginResp mobileLogin(MobileLoginReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        // 验证账号是否存在
        UserDomain userDomain = checkMobileExist(enterpriseId, req.getMobile());
        // 验证短信验证码
        validateCode(RedisKeyEnum.MOBILE_LOGIN_CODE, enterpriseId
                , req.getMobile(), req.getMobileCode());
        // 生成 token 并缓存用户信息
        String token = generateTokenAndCache(userDomain);
        // 返回数据
        return new UserLoginResp()
                .setToken(token)
                .setGender(userDomain.getGender())
                .setHeadImg(userDomain.getHeadImg())
                .setNickname(userDomain.getNickname())
                .setUserAccount(userDomain.getUserAccount());
    }

    /**
     * 邮箱登录
     *
     * @param req
     * @return com.zitangkou.user.model.resp.user.UserLoginResp
     * @author Deng Ningning
     * @date 2020/9/13 13:44
     */
    @Override
    public UserLoginResp emailLogin(EmailLoginReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        // 验证账号是否存在
        UserDomain userDomain = checkEmailExist(enterpriseId, req.getEmail());
        // 验证短信验证码
        validateCode(RedisKeyEnum.EMAIL_LOGIN_CODE, enterpriseId
                , req.getEmail(), req.getEmailCode());
        // 生成 token 并缓存用户信息
        String token = generateTokenAndCache(userDomain);
        // 返回数据
        return new UserLoginResp()
                .setToken(token)
                .setGender(userDomain.getGender())
                .setHeadImg(userDomain.getHeadImg())
                .setNickname(userDomain.getHeadImg())
                .setUserAccount(userDomain.getUserAccount());
    }

    /**
     * 绑定手机号码
     *
     * @param req
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/16 22:54
     */
    @Override
    public boolean bindMobile(MobileLoginReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        String userId = userContent.getUserIdNotNull();
        // 验证手机号码是否存在
        mobileDuplicate(enterpriseId, req.getMobile(), userId);
        // 验证短信验证码
        validateCode(RedisKeyEnum.MOBILE_BIND_CODE, enterpriseId
                , req.getMobile(), req.getMobileCode());
        // 修改
        return userDomainService.updateById(
                new UserDomain().setMobile(req.getMobile())
        );
    }

    /**
     * 绑定邮箱
     *
     * @param req
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/16 22:54
     */
    @Override
    public boolean bindEmail(EmailLoginReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        String userId = userContent.getUserIdNotNull();
        // 验证邮箱是否存在
        emailDuplicate(enterpriseId, req.getEmail(), userId);
        // 验证邮箱验证码
        validateCode(RedisKeyEnum.EMAIL_BIND_CODE, enterpriseId
                , req.getEmail(), req.getEmailCode());
        // 修改
        return userDomainService.updateById(
                new UserDomain().setEmail(req.getEmail())
        );
    }

    /**
     * 判断账号是否存在
     *
     * @param req
     * @param userContent
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/17 17:02
     */
    @Override
    public boolean accountExist(AccountExistReq req, UserContent userContent) {
        return checkUserExist(userContent.getUserIdNotNull(), req.getUserAccount()) != null;
    }

    /**
     * 判断手机号码是否存在
     *
     * @param req
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/17 17:02
     */
    @Override
    public boolean mobileExist(MobileExistReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        return checkMobileExist(enterpriseId, req.getMobile()) != null;
    }

    /**
     * 判断邮箱是否存在
     *
     * @param req
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/17 17:02
     */
    @Override
    public boolean emailExist(EmailExistReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        return checkEmailExist(enterpriseId, req.getEmail()) != null;
    }

    /**
     * 生成 token 并缓存用户信息
     *
     * @param userDomain
     * @return java.lang.String
     * @author Deng Ningning
     * @date 2020/9/12 13:02
     */
    private String generateTokenAndCache(UserDomain userDomain) {
        String token = jwtUtil.generateToken(userDomain.getEnterpriseId(), userDomain.getUserAccount());
        // 缓存用户信息
        RedisKeyEnum redisKey = RedisKeyEnum.USER_INFO_CODE;
        redisUtil.setExMinutes(String.format(redisKey.getKey(), userDomain.getEnterpriseId(), userDomain.getUserAccount())
                , new Gson().toJson(userDomain), redisKey.getMinutes());
        return token;
    }

    /**
     * 用户注册
     *
     * @param req
     * @return com.zitangkou.user.model.resp.user.UserLoginResp
     * @author Deng Ningning
     * @date 2020/9/3 10:36
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean mobileRegister(MobileRegisterReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        // 验证账号是否重复
        checkUserAccountDuplicate(enterpriseId, req.getUserAccount());
        // 验证手机号码是否重复
        mobileDuplicate(enterpriseId, req.getMobile());
        // 验证短信验证码
        validateCode(RedisKeyEnum.MOBILE_REGISTER_CODE, enterpriseId
                , req.getMobile(), req.getMobileCode());
        // 创建用户
        UserDomain userDomain = new UserDomain()
                .setEnterpriseId(enterpriseId)
                .setUserAccount(req.getUserAccount())
                .setMobile(req.getMobile())
                .setRoleId(null);
        // 密码加密
        try {
            userDomain.setUserPwd(encryptUserPwd(req.getUserPwd()));
        } catch (Exception e) {
            throw new GlobalException(RespEnum.PWD_ENCRYPT_FAIL);
        }
        return userDomainService.insertUser(userDomain);
    }

    /**
     * 用户邮箱注册
     *
     * @param req
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/11 22:34
     */
    @Override
    public boolean emailRegister(EmailRegisterReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        // 验证账号是否重复
        checkUserAccountDuplicate(enterpriseId, req.getUserAccount());
        // 验证邮箱是否重复
        emailDuplicate(enterpriseId, req.getEmail());
        // 验证邮箱验证码
        validateCode(RedisKeyEnum.EMAIL_REGISTER_CODE, enterpriseId
                , req.getEmail(), req.getEmailCode());
        // 创建用户
        UserDomain userDomain = new UserDomain()
                .setEnterpriseId(enterpriseId)
                .setUserAccount(req.getUserAccount())
                .setEmail(req.getEmail())
                .setCreateTime(LocalDateTime.now())
                .setStatus(StatusEnum.ENABLED);
        // 密码加密
        try {
            userDomain.setUserPwd(encryptUserPwd(req.getUserPwd()));
        } catch (Exception e) {
            throw new GlobalException(RespEnum.PWD_ENCRYPT_FAIL);
        }
        return userDomainService.insertUser(userDomain);
    }

    /**
     * 发送短信验证码
     *
     * @param req
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/3 11:40
     */
    @Override
    public boolean sendMobileCode(SendMobileCodeReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        // 注册时验证手机号码
        if (CodeTypeEnum.MOBILE_REGISTER.getValue().equals(req.getCodeType().getValue())) {
            mobileDuplicate(enterpriseId, req.getMobile());
        }
        // 生成验证码
        String code = RandomStringUtils.randomNumeric(6);
        log.info("向手机号码【{}】发送注册短信验证码：{}", req.getMobile(), code);
        // TODO 发送短信验证码服务接口

        // 缓存短信验证码
        sendCode(req.getCodeType(), enterpriseId, req.getMobile(), code);
        return true;
    }

    /**
     * 发送邮箱验证码
     *
     * @param req
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/11 22:19
     */
    @Override
    public boolean sendEmailCode(SendEmailCodeReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        // 生成验证码
        String code = RandomStringUtils.randomNumeric(6);
        log.info("向邮箱号码【{}】发送注册邮箱验证码：{}", req.getEmail(), code);
        // TODO 发送邮箱验证码服务接口

        // 缓存短信验证码
        sendCode(req.getCodeType(), enterpriseId, req.getEmail(), code);
        return true;
    }

    /**
     * 缓存验证码
     *
     * @param mobileCodeType
     * @param enterpriseId
     * @param mobileNumberOrEmail
     * @param code
     * @return void
     * @author Deng Ningning
     * @date 2020/9/15 11:27
     */
    private void sendCode(CodeTypeEnum mobileCodeType, String enterpriseId,
                          String mobileNumberOrEmail, String code) {
        RedisKeyEnum redisKey;
        switch (mobileCodeType) {
            // 手机号码注册
            case MOBILE_REGISTER:
                redisKey = RedisKeyEnum.MOBILE_REGISTER_CODE;
                break;
            // 邮箱注册
            case EMAIL_REGISTER:
                redisKey = RedisKeyEnum.EMAIL_REGISTER_CODE;
                break;
            // 手机号码登录
            case MOBILE_LOGIN:
                redisKey = RedisKeyEnum.MOBILE_LOGIN_CODE;
                break;
            // 邮箱登录
            case EMAIL_LOGIN:
                redisKey = RedisKeyEnum.EMAIL_LOGIN_CODE;
                break;
            // 手机绑定
            case MOBILE_BIND:
                redisKey = RedisKeyEnum.MOBILE_BIND_CODE;
                break;
            // 邮箱绑定
            case EMAIL_BIND:
                redisKey = RedisKeyEnum.EMAIL_BIND_CODE;
                break;
            // 忘记密码
            case FORGOT_PASSWORD:
                redisKey = RedisKeyEnum.FORGOT_PASSWORD_CODE;
                break;
            default:
                throw new GlobalException(RespEnum.CODE_TYPE_NOT_EXIST);
        }
        redisUtil.setExMinutes(String.format(redisKey.getKey(), enterpriseId, mobileNumberOrEmail)
                , code, redisKey.getMinutes());
    }

    /**
     * 验证同一企业内账号唯一，返回对象
     *
     * @param userAccount
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/3 11:23
     */
    @Override
    public UserDomain selectByUserAccount(String enterpriseId, String userAccount) {
        return userDomainService.selectOneByConditions(new UserDomain().setEnterpriseId(enterpriseId).setUserAccount(userAccount));
    }

    /**
     * 验证密码
     *
     * @param userDomain
     * @param userPwd
     * @return void
     * @author Deng Ningning
     * @date 2020/9/3 16:20
     */
    private void validateUserPwd(UserDomain userDomain, String userPwd) {
        String encryptUserPwd = encryptUserPwd(userPwd);
        if (StringUtils.isEmpty(encryptUserPwd)
                || !encryptUserPwd.equals(userDomain.getUserPwd())) {
            throw new GlobalException(RespEnum.USER_PWD_ERROR);
        }
    }

    /**
     * 验证短信验证码
     *
     * @param redisKey
     * @param enterpriseId
     * @param mobile
     * @param mobileCode
     * @return void
     * @author Deng Ningning
     * @date 2020/9/3 14:13
     */
    private void validateCode(RedisKeyEnum redisKey, String enterpriseId
            , String mobile, String mobileCode) {
        String code = redisUtil.get(String.format(redisKey.getKey(), enterpriseId, mobile));
        if (StringUtils.isEmpty(code)) {
            throw new GlobalException(RespEnum.CODE_INVALID);
        }
        if (!code.equals(mobileCode)) {
            throw new GlobalException(RespEnum.CODE_ERROR);
        }
    }

    /**
     * 密码加密
     *
     * @param userPwd
     * @return java.lang.String
     * @author Deng Ningning
     * @date 2020/9/3 16:38
     */
    private String encryptUserPwd(String userPwd) {
        String encryptUserPwd;
        try {
            encryptUserPwd = Base64.getEncoder().encodeToString(
                    CryptUtil.encryptOrDecrypt(userPwd.getBytes(), SecretEnum.TOKEN_SECRET
                            , CipherAlgorithmEnum.DES_CIPHER_ALGORITHM, Cipher.ENCRYPT_MODE
                    )
            );
        } catch (Exception e) {
            throw new GlobalException(RespEnum.PWD_ENCRYPT_FAIL);
        }
        return encryptUserPwd;
    }

    /**
     * 验证同一企业内手机号码唯一，抛出异常
     *
     * @param enterpriseId
     * @param mobile
     * @return void
     * @author Deng Ningning
     * @date 2020/9/3 11:23
     */
    private void mobileDuplicate(String enterpriseId, String mobile) {
        if (isMobileDuplicate(enterpriseId, mobile)) {
            throw new GlobalException(RespEnum.MOBILE_DUPLICATE);
        }
    }

    /**
     * 验证同一企业内手机号码唯一，抛出异常
     *
     * @param enterpriseId
     * @param mobile
     * @return void
     * @author Deng Ningning
     * @date 2020/9/3 11:23
     */
    private void mobileDuplicate(String enterpriseId, String mobile, String userId) {
        if (isMobileDuplicate(enterpriseId, mobile, userId)) {
            throw new GlobalException(RespEnum.MOBILE_DUPLICATE);
        }
    }

    /**
     * 验证邮箱是否重复
     *
     * @param enterpriseId
     * @param email
     * @return void
     * @author Deng Ningning
     * @date 2020/9/11 22:34
     */
    private void emailDuplicate(String enterpriseId, String email) {
        if (isEmailDuplicate(enterpriseId, email)) {
            throw new GlobalException(RespEnum.EMAIL_DUPLICATE);
        }
    }

    private void emailDuplicate(String enterpriseId, String email, String userId) {
        if (isEmailDuplicate(enterpriseId, email, userId)) {
            throw new GlobalException(RespEnum.EMAIL_DUPLICATE);
        }
    }

    /**
     * 验证同一企业内手机号码唯一，返回
     *
     * @param enterpriseId
     * @param mobile
     * @param userId
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/16 23:06
     */
    private boolean isMobileDuplicate(String enterpriseId, String mobile, String userId) {
        UserDomain userDomain = new UserDomain();
        userDomain.setEnterpriseId(enterpriseId);
        userDomain.setMobile(mobile);
        userDomain.setUserId(userId);
        return userDomainService.countByConditions(userDomain) > 0;
    }

    /**
     * 验证同一企业内手机号码唯一，返回
     *
     * @param enterpriseId
     * @param mobile
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/3 11:23
     */
    private boolean isMobileDuplicate(String enterpriseId, String mobile) {
        return isMobileDuplicate(enterpriseId, mobile, null);
    }

    /**
     * 验证邮箱是否重复
     *
     * @param enterpriseId
     * @param email
     * @return boolean
     * @author Deng Ningning
     * @date 2020/9/11 22:35
     */
    private boolean isEmailDuplicate(String enterpriseId, String email) {
        return userDomainService.countByConditions(new UserDomain().setEnterpriseId(enterpriseId).setEmail(email)) > 0;
    }

    private boolean isEmailDuplicate(String enterpriseId, String email, String userId) {
        UserDomain userDomain = new UserDomain();
        userDomain.setEnterpriseId(enterpriseId);
        userDomain.setEmail(email);
        userDomain.setUserId(userId);
        return userDomainService.countByConditions(userDomain) > 0;
    }

    /**
     * 验证同一企业内账号唯一，抛出异常
     *
     * @param enterpriseId
     * @param userAccount
     * @return void
     * @author Deng Ningning
     * @date 2020/9/3 11:23
     */
    private void checkUserAccountDuplicate(String enterpriseId, String userAccount) {
        UserDomain userDomain = selectByUserAccount(enterpriseId, userAccount);
        if (null != userDomain) {
            throw new GlobalException(RespEnum.USER_ACCOUNT_DUPLICATE);
        }
    }

    /**
     * 验证用户是否存在
     *
     * @param userAccount
     * @return top.zitangkou.user.model.entity.UserDO
     * @author Deng Ningning
     * @date 2020/9/3 17:13
     */
    private UserDomain checkUserExist(String enterpriseId, String userAccount) {
        UserDomain userDomain = selectByUserAccount(enterpriseId, userAccount);
        if (null == userDomain) {
            throw new GlobalException(RespEnum.USER_NOT_EXIST);
        }
        return userDomain;
    }

    /**
     * 根据手机号码查询用户
     *
     * @param enterpriseId
     * @param mobile
     * @return top.zitangkou.user.model.entity.UserDO
     * @author Deng Ningning
     * @date 2020/9/12 12:50
     */
    private UserDomain checkMobileExist(String enterpriseId, String mobile) {
        UserDomain userDomain = selectByMobileNumber(enterpriseId, mobile);
        if (null == userDomain) {
            throw new GlobalException(RespEnum.USER_NOT_EXIST);
        }
        return userDomain;
    }

    /**
     * 判断用户是否存在
     *
     * @param enterpriseId
     * @param email
     * @return top.zitangkou.user.model.entity.UserDO
     * @author Deng Ningning
     * @date 2020/9/13 13:47
     */
    private UserDomain checkEmailExist(String enterpriseId, String email) {
        UserDomain userDomain = selectByEmail(enterpriseId, email);
        if (null == userDomain) {
            throw new GlobalException(RespEnum.USER_NOT_EXIST);
        }
        return userDomain;
    }

    /**
     * 根据手机号码查询用户
     *
     * @param enterpriseId
     * @param mobile
     * @return top.zitangkou.user.model.entity.UserDO
     * @author Deng Ningning
     * @date 2020/9/12 12:53
     */
    public UserDomain selectByMobileNumber(String enterpriseId, String mobile) {
        return userDomainService.selectOneByConditions(new UserDomain().setEnterpriseId(enterpriseId).setMobile(mobile));
    }

    /**
     * 根据邮箱查询用户
     *
     * @param enterpriseId
     * @param email
     * @return top.zitangkou.user.model.entity.UserDO
     * @author Deng Ningning
     * @date 2020/9/13 13:46
     */
    public UserDomain selectByEmail(String enterpriseId, String email) {
        return userDomainService.selectOneByConditions(new UserDomain().setEnterpriseId(enterpriseId).setEmail(email));
    }

    /**
     * 查询常量
     *
     * @param type
     * @return top.zitangkou.user.model.resp.user.ConstantListResp
     * @author Deng Ningning
     * @date 2020/9/29 20:25
     */
    @Override
    public ConstantListResp getConstants(String type) {
        ConstantListResp resp = new ConstantListResp();
        // 查询缓存
        RedisKeyEnum redisKeyEnum = RedisKeyEnum.USER_CONSTANT;
        String key = String.format(redisKeyEnum.getKey(), type);
        String value = redisUtil.get(key);
        if (StringUtils.isEmpty(value)) {
            return resp.setList(new ArrayList<>());
        }
        List<ConstantResp> list;
        try {
            list = JSON.parseArray(value, ConstantResp.class);
        } catch (Exception e) {
            throw new GlobalException(RespEnum.USER_CONSTANT_FAIL);
        }
        if (CollectionUtils.isEmpty(list)) {
            return resp.setList(list);
        }
        // 查询枚举
        UserEnum userEnum;
        try {
            userEnum = UserEnum.valueOf(type);
        } catch (Exception e) {
            throw new GlobalException(RespEnum.USER_CONSTANT_FAIL);
        }
        switch (userEnum) {
            case GENDER:
                list = Arrays.stream(GenderEnum.values())
                        .map(a -> new ConstantResp().setCode(a.getValue()).setDesc(a.getRemark()))
                        .collect(Collectors.toList());
                break;
            default:
                throw new GlobalException(RespEnum.USER_CONSTANT_FAIL);
        }
        // 保存缓存
        redisUtil.setExMinutes(key, JSON.toJSONString(list), redisKeyEnum.getMinutes());
        return resp.setList(list);
    }

    /**
     * 查询当前用户
     *
     * @return top.zitangkou.user.model.resp.user.UserLoginResp
     * @author Deng Ningning
     * @date 2020/10/28 22:26
     */
    @Override
    public UserLoginResp getUserInfo(UserContent userContent) {
        String userId = userContent.getUserIdNotNull();
        UserDomain userDomain = userDomainService.getUserById(userId);
        // 查询用户角色
        RedisKeyEnum redisKey = RedisKeyEnum.USER_ROLE_CONSTANT;
        String code = redisUtil.get(String.format(redisKey.getKey(), userId));
        RoleInfo roleInfo;
        if (StringUtils.isNotBlank(code)) {
            roleInfo = JSON.parseObject(code, RoleInfo.class);
        } else {
            RoleDomain roleDomain = roleDomainService.getRoleById(userDomain.getRoleId());
            roleInfo = roleInfoConverter.toInfo(roleDomain);
            List<UserPermissionDomain> userPermissionDomainList =
                    userPermissionDomainService.selectPermissionsByUserId(userDomain.getUserId());
            if (CollectionUtils.isEmpty(userPermissionDomainList)) {
                roleInfo.setPermissions(new ArrayList<>());
            } else {
                List<PermissionDomain> permissionDomainList = permissionDomainService.selectPermissionsByIdList(
                        userPermissionDomainList.stream().map(UserPermissionDomain::getPermissionId).collect(
                                Collectors.toList()));
                roleInfo.setPermissions(permissionInfoConverter.toInfoList(permissionDomainList));
            }
        }
        redisUtil.setExMinutes(String.format(redisKey.getKey(), userId), JSON.toJSONString(roleInfo), redisKey.getMinutes());
        // 返回数据
        return new UserLoginResp()
                .setGender(userDomain.getGender())
                .setHeadImg(userDomain.getHeadImg())
                .setNickname(userDomain.getNickname())
                .setUserAccount(userDomain.getUserAccount())
                .setRole(roleInfo);
    }

    /**
     * 退出登录
     *
     * @return boolean
     * @author Deng Ningning
     * @date 2020/10/30 13:39
     */
    @Override
    public boolean loginOut(UserContent userContent) {
        String userId = userContent.getUserIdNotNull();
        UserDomain userDomain = userDomainService.getUserById(userId);
        // 用户登出时会清除缓存
        redisUtil.delete(String.format(RedisKeyEnum.USER_INFO_CODE.getKey(),
                userDomain.getEnterpriseId(), userDomain.getUserAccount()));
        return true;
    }

    @Override
    public boolean forgotPassword(ForgotPasswordReq req, UserContent userContent) {
        String enterpriseId = userContent.getEnterpriseIdNotNull();
        // 验证手机号码是否重复
        UserDomain userDoOld = checkMobileExist(enterpriseId, req.getMobile());
        // 验证短信验证码
        validateCode(RedisKeyEnum.FORGOT_PASSWORD_CODE, enterpriseId
                , req.getMobile(), req.getMobileCode());
        // 密码加密
        try {
            req.setUserPwd(encryptUserPwd(req.getUserPwd()));
        } catch (Exception e) {
            throw new GlobalException(RespEnum.PWD_ENCRYPT_FAIL);
        }
        // 创建用户
        UserDomain userDomain = new UserDomain()
                .setUserId(userDoOld.getUserId())
                .setUserPwd(req.getUserPwd());
        return userDomainService.updateById(userDomain);
    }

    @Override
    public UserInfo getUserById(String userId) {
        return userInfoConverter.toInfo(userDomainService.getUserById(userId));
    }

    @Override
    @Async("imThreadPoolExecutor")
    public void consumeMsg(int i) {
        log.info("创建线程池开始执行第" + i + "次任务");
        Set<String> messages;
        String message;
        Double score;
        String key = "TEST";
        Long flag;
        ZSetOperations zSetOperations = redisTemplate.opsForZSet();
        messages = zSetOperations.rangeByScore(key, 0, System.currentTimeMillis() / 1000D);
        log.info("当前线程：" + Thread.currentThread().getName());
        if (CollectionUtils.isEmpty(messages)) {
            log.info("查询无数据，休息1s继续下次消费");
            // 没有到期的消息，休息1s再继续
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return;
        }
        log.info("查询到消息，准备消费");
        // 消费消息
        message = messages.iterator().next();
        score = zSetOperations.score(key, message);
        // 删除队列中消息
        flag = zSetOperations.remove(key, message);
        if (flag != null && flag > 0) {
            log.info("消费成功，删除消息");
            System.out.println("线程（" + Thread.currentThread().getName() + "）消费消息：【" + message + "】");
            System.out.println("当前消息分值：" + score + "，当前时间：" + System.currentTimeMillis() / 1000);
        }
    }

    @Override
    public void produceMsg(int msgNum) {
        String key = "TEST";
        ProductThread productThread = new ProductThread(msgNum, key);
        Thread thread = new Thread(productThread);
        thread.start();
    }

    @Data
    @AllArgsConstructor
    class ProductThread implements Runnable {

        private int msgNum;

        private String key;

        @Override
        public void run() {
            String msg;
            int time;
            log.info("开始生产消息");
            for (int i = 0; i < msgNum; i++) {
                msg = "第" + (i + 1) + "条消息，线程（" + Thread.currentThread().getName() + "）：" + UuidUtils.generateUuid();
                redisTemplate.opsForZSet().add(key, msg, System.currentTimeMillis() / 1000D + 60);
                log.info("发送消息【" + msg + "】");
                try {
                    time = RandomUtils.nextInt(1, 20);
                    log.info("休息" + time + "秒");
                    Thread.sleep(time * 1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    log.info(e.getMessage());
                }
            }
        }
    }
}
